﻿using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using RaytracerLib.MathLib;
using TomanuExtensions;
using RaytracerLib;
using System;
using RaytracerLib.MathLib.Polynomials;

namespace RaytracerTest
{
    [TestClass]
    public class PolynomialTest : TestBase
    {
        [TestMethod]
        public void Polynomial_Test()
        {
            Polynomial p_1 = new Polynomial(-1.0, 1.0) * 2;
            Polynomial p_2 = new Polynomial(-2.0, 1.0) * -0.3;
            Polynomial p_3 = new Polynomial(-3.0, 1.0) * -3;
            Polynomial p_4 = new Polynomial(-4.0, 1.0) * 0.2;
            Polynomial p_5 = new Polynomial(-5.0, 1.0) * 1.2;
            Polynomial p_6 = new Polynomial(-6.0, 1.0) * -3.2;

            // Constructors.

            {
                Polynomial p = new Polynomial();
                Assert.IsTrue(p.Order == 0);
            }

            {
                Polynomial p = new Polynomial(1.2);
                Assert.IsTrue(p.Order == 0);
                Assert.IsTrue(p[0].IsAlmostEquals(1.2));
                Assert.IsTrue(p.LeadCoefficient.IsAlmostEquals(1.2));
                Assert.IsTrue(p.LastCoefficient.IsAlmostEquals(1.2));
            }

            {
                Polynomial p = new Polynomial(1.3, 1.2);
                Assert.IsTrue(p.Order == 1);
                Assert.IsTrue(p[1].IsAlmostEquals(1.2));
                Assert.IsTrue(p[0].IsAlmostEquals(1.3));
                Assert.IsTrue(p.LeadCoefficient.IsAlmostEquals(1.2));
                Assert.IsTrue(p.LastCoefficient.IsAlmostEquals(1.3));
            }

            {
                Polynomial p = new Polynomial(1.4, 1.3, 1.2);
                Assert.IsTrue(p.Order == 2);
                Assert.IsTrue(p[2].IsAlmostEquals(1.2));
                Assert.IsTrue(p[1].IsAlmostEquals(1.3));
                Assert.IsTrue(p[0].IsAlmostEquals(1.4));
                Assert.IsTrue(p.LeadCoefficient.IsAlmostEquals(1.2));
                Assert.IsTrue(p.LastCoefficient.IsAlmostEquals(1.4));
            }

            {
                Polynomial p = new Polynomial(1.5, 1.4, 1.3, 1.2);
                Assert.IsTrue(p.Order == 3);
                Assert.IsTrue(p[3].IsAlmostEquals(1.2));
                Assert.IsTrue(p[2].IsAlmostEquals(1.3));
                Assert.IsTrue(p[1].IsAlmostEquals(1.4));
                Assert.IsTrue(p[0].IsAlmostEquals(1.5));
                Assert.IsTrue(p.LeadCoefficient.IsAlmostEquals(1.2));
                Assert.IsTrue(p.LastCoefficient.IsAlmostEquals(1.5));
            }

            {
                Polynomial p = new Polynomial(1.6, 1.5, 1.4, 1.3, 1.2);
                Assert.IsTrue(p.Order == 4);
                Assert.IsTrue(p[4].IsAlmostEquals(1.2));
                Assert.IsTrue(p[3].IsAlmostEquals(1.3));
                Assert.IsTrue(p[2].IsAlmostEquals(1.4));
                Assert.IsTrue(p[1].IsAlmostEquals(1.5));
                Assert.IsTrue(p[0].IsAlmostEquals(1.6));
                Assert.IsTrue(p.LeadCoefficient.IsAlmostEquals(1.2));
                Assert.IsTrue(p.LastCoefficient.IsAlmostEquals(1.6));
            }

            {
                Polynomial p = new Polynomial(1.7, 1.6, 1.5, 1.4, 1.3, 1.2, 1.21, 1.22);
                Assert.IsTrue(p.Order == 7);
                Assert.IsTrue(p[7].IsAlmostEquals(1.22));
                Assert.IsTrue(p[6].IsAlmostEquals(1.21));
                Assert.IsTrue(p[5].IsAlmostEquals(1.2));
                Assert.IsTrue(p[4].IsAlmostEquals(1.3));
                Assert.IsTrue(p[3].IsAlmostEquals(1.4));
                Assert.IsTrue(p[2].IsAlmostEquals(1.5));
                Assert.IsTrue(p[1].IsAlmostEquals(1.6));
                Assert.IsTrue(p[0].IsAlmostEquals(1.7));
                Assert.IsTrue(p.LeadCoefficient.IsAlmostEquals(1.22));
                Assert.IsTrue(p.LastCoefficient.IsAlmostEquals(1.7));
            }

            {
                Polynomial p = new Polynomial(new double[] 
                { 1.7, 1.6, 1.5, 1.4, 1.3, 1.2 });
                Assert.IsTrue(p.Order == 5);
                Assert.IsTrue(p[5].IsAlmostEquals(1.2));
                Assert.IsTrue(p[4].IsAlmostEquals(1.3));
                Assert.IsTrue(p[3].IsAlmostEquals(1.4));
                Assert.IsTrue(p[2].IsAlmostEquals(1.5));
                Assert.IsTrue(p[1].IsAlmostEquals(1.6));
                Assert.IsTrue(p[0].IsAlmostEquals(1.7));
                Assert.IsTrue(p.LeadCoefficient.IsAlmostEquals(1.2));
                Assert.IsTrue(p.LastCoefficient.IsAlmostEquals(1.7));
            }

            {
                Polynomial p = new Polynomial(1.6, 1.5, 1.4, 1.3, 0);
                Assert.IsTrue(p.Order == 3);
                Assert.IsTrue(p[3].IsAlmostEquals(1.3));
                Assert.IsTrue(p[2].IsAlmostEquals(1.4));
                Assert.IsTrue(p[1].IsAlmostEquals(1.5));
                Assert.IsTrue(p[0].IsAlmostEquals(1.6));
                Assert.IsTrue(p.LeadCoefficient.IsAlmostEquals(1.3));
                Assert.IsTrue(p.LastCoefficient.IsAlmostEquals(1.6));
            }

            {
                Polynomial p = new Polynomial(0.0);
                Assert.IsTrue(p.Order == 0);
                Assert.IsTrue(p[0].IsAlmostEquals(0.0));
                Assert.IsTrue(p.LeadCoefficient.IsAlmostEquals(0.0));
                Assert.IsTrue(p.LastCoefficient.IsAlmostEquals(0.0));
            }

            // Equals(obj), Equals(Polynomial), ==, !=

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, -1.4, 1.3, 1.2);
                Polynomial p2 = new Polynomial(1.6, 1.5, -1.4, 1.3, 1.2);

                Assert.IsTrue(p1 == p2);
                Assert.IsTrue(p2 == p1);
                Assert.IsFalse(p1 != p2);
                Assert.IsFalse(p2 != p1);
                Assert.AreEqual(p1, p2);
                Assert.AreEqual(p2, p1);
                Assert.AreEqual((object)p1, (object)p2);
                Assert.AreEqual((object)p2, (object)p1);

                Assert.AreEqual(new Polynomial(1.6, 1.5, -1.4, 1.3, 1.2), p1);
                Assert.AreEqual(new Polynomial(1.6, 1.5, -1.4, 1.3, 1.2), p2);
            }

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, 1.4, 1.3, -1.21);
                Polynomial p2 = new Polynomial(1.6, 1.5, 1.4, 1.3, -1.2);

                Assert.IsFalse(p1 == p2);
                Assert.IsFalse(p2 == p1);
                Assert.IsTrue(p1 != p2);
                Assert.IsTrue(p2 != p1);
                Assert.AreNotEqual(p1, p2);
                Assert.AreNotEqual(p2, p1);
                Assert.AreNotEqual((object)p1, (object)p2);
                Assert.AreNotEqual((object)p2, (object)p1);
            }

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, 1.4, 1.3);
                Polynomial p2 = new Polynomial(1.6, 1.5, 1.4, 1.3, 1.2);

                Assert.IsFalse(p1 == p2);
                Assert.IsFalse(p2 == p1);
                Assert.IsTrue(p1 != p2);
                Assert.IsTrue(p2 != p1);
                Assert.AreNotEqual(p1, p2);
                Assert.AreNotEqual(p2, p1);
                Assert.AreNotEqual((object)p1, (object)p2);
                Assert.AreNotEqual((object)p2, (object)p1);
            }

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, -1.4, -1.3);
                Polynomial p2 = new Polynomial(1.6, 1.5, -1.4, -1.3, 0);

                Assert.IsTrue(p1 == p2);
                Assert.IsTrue(p2 == p1);
                Assert.IsFalse(p1 != p2);
                Assert.IsFalse(p2 != p1);
                Assert.AreEqual(p1, p2);
                Assert.AreEqual(p2, p1);
                Assert.AreEqual((object)p1, (object)p2);
                Assert.AreEqual((object)p2, (object)p1);
            }

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, 1.4, 1.3, 1.2);
                Polynomial p2 = new Polynomial(1.6 / 1.2, 1.5 / 1.2, 1.4 / 1.2, 1.3 / 1.2, 1);

                Assert.IsFalse(p1 == p2);
                Assert.IsFalse(p2 == p1);
                Assert.IsTrue(p1 != p2);
                Assert.IsTrue(p2 != p1);
                Assert.AreNotEqual(p1, p2);
                Assert.AreNotEqual(p2, p1);
                Assert.AreNotEqual((object)p1, (object)p2);
                Assert.AreNotEqual((object)p2, (object)p1);
            }

            // Copying constructor.

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, -1.4, 1.3, 1.2);
                Polynomial p2 = new Polynomial(p1);

                Assert.AreEqual(p1, p2);
                Assert.AreEqual(new Polynomial(1.6, 1.5, -1.4, 1.3, 1.2), p1);
            }

            // IsAlmostRelativeEquals

            {
                Polynomial p1 = new Polynomial(0);
                Polynomial p2 = new Polynomial(1);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == false);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(0);
                Polynomial p2 = new Polynomial(0);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(0);
                Polynomial p2 = new Polynomial(Constants.DOUBLE_PRECISION / 2);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(0);
                Polynomial p2 = new Polynomial(Constants.DOUBLE_PRECISION * 2);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == false);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1);
                Polynomial p2 = new Polynomial(Constants.DOUBLE_PRECISION / 2);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == false);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1);
                Polynomial p2 = new Polynomial(Constants.DOUBLE_PRECISION * 2);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == false);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1);
                Polynomial p2 = new Polynomial(1 + Constants.DOUBLE_PRECISION / 2);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1);
                Polynomial p2 = new Polynomial(1 + Constants.DOUBLE_PRECISION * 2);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == false);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1, 0);
                Polynomial p2 = new Polynomial(1);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1, 0, 0);
                Polynomial p2 = new Polynomial(1);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1, 0, 0);
                Polynomial p2 = new Polynomial(1, 0);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1, 0, 0);
                Polynomial p2 = new Polynomial(1, 0, 0);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(2, 3);
                Polynomial p2 = new Polynomial(2, 3);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(2, 3, 0);
                Polynomial p2 = new Polynomial(2, 3);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(2, 3, 0, 0);
                Polynomial p2 = new Polynomial(2, 3);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(2, 3, 0, 0);
                Polynomial p2 = new Polynomial(2, 3);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(2, 3, 0, Constants.DOUBLE_PRECISION / 2);
                Polynomial p2 = new Polynomial(2, 3);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(2, 3, 0, Constants.DOUBLE_PRECISION * 2);
                Polynomial p2 = new Polynomial(2, 3);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == false);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1 / Constants.DOUBLE_PRECISION, 3);
                Polynomial p2 = new Polynomial(1 / Constants.DOUBLE_PRECISION - 0.5, 3);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1 / Constants.DOUBLE_PRECISION, 3);
                Polynomial p2 = new Polynomial(1 / Constants.DOUBLE_PRECISION - 2, 3);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == false);
                Assert.IsTrue(p1.IsAlmostRelativeEquals(p2) == p2.IsAlmostRelativeEquals(p1));
            }

            // IsAlmostEquals.

            {
                Polynomial p1 = new Polynomial(0);
                Polynomial p2 = new Polynomial(1);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == false);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(0);
                Polynomial p2 = new Polynomial(0);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(0);
                Polynomial p2 = new Polynomial(Constants.DOUBLE_PRECISION / 2);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(0);
                Polynomial p2 = new Polynomial(Constants.DOUBLE_PRECISION * 2);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == false);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1);
                Polynomial p2 = new Polynomial(Constants.DOUBLE_PRECISION / 2);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == false);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1);
                Polynomial p2 = new Polynomial(Constants.DOUBLE_PRECISION * 2);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == false);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1);
                Polynomial p2 = new Polynomial(1 + Constants.DOUBLE_PRECISION / 2);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1);
                Polynomial p2 = new Polynomial(1 + Constants.DOUBLE_PRECISION * 2);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == false);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1, 0);
                Polynomial p2 = new Polynomial(1);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1, 0, 0);
                Polynomial p2 = new Polynomial(1);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1, 0, 0);
                Polynomial p2 = new Polynomial(1, 0);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1, 0, 0);
                Polynomial p2 = new Polynomial(1, 0, 0);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(2, 3);
                Polynomial p2 = new Polynomial(2, 3);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(2, 3, 0);
                Polynomial p2 = new Polynomial(2, 3);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(2, 3, 0, 0);
                Polynomial p2 = new Polynomial(2, 3);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(2, 3, 0, 0);
                Polynomial p2 = new Polynomial(2, 3);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(2, 3, 0, Constants.DOUBLE_PRECISION / 2);
                Polynomial p2 = new Polynomial(2, 3);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == true);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(2, 3, 0, Constants.DOUBLE_PRECISION * 2);
                Polynomial p2 = new Polynomial(2, 3);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == false);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1 / Constants.DOUBLE_PRECISION, 3);
                Polynomial p2 = new Polynomial(1 / Constants.DOUBLE_PRECISION - 0.5, 3);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == false);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1 / Constants.DOUBLE_PRECISION, 3);
                Polynomial p2 = new Polynomial(1 / Constants.DOUBLE_PRECISION - 2, 3);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == false);
                Assert.IsTrue(p1.IsAlmostEquals(p2) == p2.IsAlmostEquals(p1));
            }

            {
                Polynomial p1 = new Polynomial(1 / 1e-6, 3);
                Polynomial p2 = new Polynomial(1 / 1e-6 - 0.5 * 1e-6, 3);
                Assert.IsTrue(p1.IsAlmostEquals(p2, 1e-6) == true);
                Assert.IsTrue(p1.IsAlmostEquals(p2, 1e-6) == p2.IsAlmostEquals(p1, 1e-6));
            }

            {
                Polynomial p1 = new Polynomial(1 / 1e-6, 3);
                Polynomial p2 = new Polynomial(1 / 1e-6 - 2 * 1e-6, 3);
                Assert.IsTrue(p1.IsAlmostEquals(p2, 1e-6) == false);
                Assert.IsTrue(p1.IsAlmostEquals(p2, 1e-6) == p2.IsAlmostEquals(p1, 1e-6));
            }

            // Evaluate.

            {
                AreAlmostRelativeEquals(2.0, new Polynomial(2).Evaluate(2.1));
                AreAlmostRelativeEquals(7.2, new Polynomial(3, 2).Evaluate(2.1));
                AreAlmostRelativeEquals(19.12, new Polynomial(4, 3, 2).Evaluate(2.1));
                AreAlmostRelativeEquals(28.352000000000004, new Polynomial(5, -4, 3, 2).Evaluate(2.1));
                AreAlmostRelativeEquals(100.81920000000001, new Polynomial(6, 5, 4, 3, 2).Evaluate(2.1));
                AreAlmostRelativeEquals(-6.0, new Polynomial(-6, 5, 4, -3, 2).Evaluate(0));
                AreAlmostRelativeEquals(24.253200000000003, new Polynomial(6, 5, 4, 3, 2).Evaluate(-2.1));
                AreAlmostRelativeEquals(17.807100000000005, new Polynomial(6 / 2, 5 / 2, 4 / 2, 3 / 2, 1).Evaluate(-2.1));
                AreAlmostRelativeEquals(45.152, new Polynomial(5, 4, 3, 2, 0).Evaluate(2.1));
                AreAlmostRelativeEquals(19.12, new Polynomial(4, 3, 2, 0, 0).Evaluate(2.1));

                Polynomial p = new Polynomial(4, 3, 2, 0, 0);
                double x = p.Evaluate(4.4);
                Assert.AreEqual(new Polynomial(4, 3, 2, 0, 0), p);
            }

            // Diffrentatie.

            {
                AreAlmostRelativeEquals(0.0, new Polynomial().Differentiate().Evaluate(2.1));
                AreAlmostRelativeEquals(0, new Polynomial(2).Differentiate().Evaluate(2.1));
                AreAlmostRelativeEquals(2.0, new Polynomial(-3, 2).Differentiate().Evaluate(2.1));
                AreAlmostRelativeEquals(11.4, new Polynomial(4, 3, 2).Differentiate().Evaluate(2.1));
                AreAlmostRelativeEquals(17.860000000000003, new Polynomial(5, 4, -3, 2).Differentiate().Evaluate(2.1));
                AreAlmostRelativeEquals(135.57800000000003, new Polynomial(6, 5, 4, 3, 2).Differentiate().Evaluate(2.1));
                AreAlmostRelativeEquals(5, new Polynomial(6, 5, 4, -3, 2).Differentiate().Evaluate(0));
                AreAlmostRelativeEquals(-46.198000000000008, new Polynomial(6, 5, 4, 3, 2).Differentiate().Evaluate(-2.1));
                AreAlmostRelativeEquals(-30.214000000000006, new Polynomial(6 / 2, 5 / 2, 4 / 2, 3 / 2, 1).Differentiate().Evaluate(-2.1));
                AreAlmostRelativeEquals(43.06, new Polynomial(5, 4, 3, 2, 0).Differentiate().Evaluate(2.1));
                AreAlmostRelativeEquals(11.4, new Polynomial(4, 3, 2, 0, 0).Differentiate().Evaluate(2.1));

                Polynomial p = new Polynomial(6, 5, 4, -3, 2);
                Polynomial d = p.Differentiate();
                Assert.AreEqual(new Polynomial(6, 5, 4, -3, 2), p);
            }

            // Normalize.

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, 1.4, 1.3, 1.2).Normalize();
                Polynomial p2 = new Polynomial(1.6 / 1.2, 1.5 / 1.2, 1.4 / 1.2, 1.3 / 1.2, 1);

                Assert.AreEqual(p1, p2);
            }

            {
                Polynomial p = new Polynomial(1.6, 1.5, 1.4, 1.3, -1.2);
                Polynomial p1 = p.Normalize();
                Polynomial p2 = new Polynomial(1.6 / -1.2, 1.5 / -1.2, 1.4 / -1.2, 1.3 / -1.2, 1);

                Assert.AreEqual(p1, p2);
                Assert.AreEqual(p, new Polynomial(1.6, 1.5, 1.4, 1.3, -1.2));
            }

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, 1.4, 1.3, 0).Normalize();
                Polynomial p2 = new Polynomial(1.6, 1.5, 1.4, 1.3, 0);

                Assert.AreNotEqual(p1, p2);
            }

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, -1.4, 1.3, 0).Normalize();
                Polynomial p2 = new Polynomial(1.6 / 1.3, 1.5 / 1.3, -1.4 / 1.3, 1);

                Assert.AreEqual(p1, p2);
            }

            // operator / , DivRem(Rem)

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, 1.4, 1.3, 1.2);
                Polynomial p2 = new Polynomial(1.6, 1.5, 1.4, 1.3, 1.2);

                Polynomial p3 = p1 / p2;
                Polynomial rem;
                Polynomial p4 = Polynomial.DivRem(p1, p2, out rem);

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(new Polynomial(1.0), p3);

                Assert.AreEqual(new Polynomial(1.6, 1.5, 1.4, 1.3, 1.2), p1);
                Assert.AreEqual(new Polynomial(1.6, 1.5, 1.4, 1.3, 1.2), p2);
            }

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, 1.4, 1.3, 1.2);
                Polynomial p2 = new Polynomial(1.6, 1.5, 1.4, 1.3);

                Polynomial p3 = p1 / p2;
                Polynomial rem;
                Polynomial p4 = Polynomial.DivRem(p1, p2, out rem);

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(new Polynomial(0.0059171597633137594, 0.923076923076923), p3);
            }

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, 1.4, 1.3, 1.2);
                Polynomial p2 = new Polynomial(1.6, 1.5, 1.4);

                Polynomial p3 = p1 / p2;
                Polynomial rem;
                Polynomial p4 = Polynomial.DivRem(p1, p2, out rem);

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(new Polynomial(0.00947521865889193, 0.010204081632653, 0.857142857142857), p3);
            }

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, 1.4, -1.3, 1.2);
                Polynomial p2 = new Polynomial(1.6, 1.5);

                Polynomial p3 = p1 / p2;
                Polynomial rem;
                Polynomial p4 = Polynomial.DivRem(p1, p2, out rem);

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(new Polynomial(-1.95253333333333, 2.768, -1.72, 0.8), p3);
            }

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, -1.4, 1.3, 1.2);
                Polynomial p2 = new Polynomial(1.6);

                Polynomial p3 = p1 / p2;
                Polynomial rem;
                Polynomial p4 = Polynomial.DivRem(p1, p2, out rem);

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(new Polynomial(1, 0.9375, -0.875, 0.8125, 0.75), p3);
            }

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, 1.4, 1.3);
                Polynomial p2 = new Polynomial(1.6, 1.5, 1.4, 1.3, 1.2);

                Polynomial p3 = p1 / p2;
                Polynomial rem;
                Polynomial p4 = Polynomial.DivRem(p1, p2, out rem);

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(Polynomial.ZERO, p3);
            }

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, 1.4, 1.3, 0);
                Polynomial p2 = new Polynomial(1.6, 1.5, 1.4, 1.3);

                Polynomial p3 = p1 / p2;
                Polynomial rem;
                Polynomial p4 = Polynomial.DivRem(p1, p2, out rem);

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(new Polynomial(1.0), p3);
            }

            // operator %, DivRem(div)

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, 1.4, 1.3, 1.2);
                Polynomial p2 = new Polynomial(1.6, 1.5, 1.4, 1.3, 1.2);

                Polynomial p3 = p1 % p2;
                Polynomial rem;
                Polynomial.DivRem(p1, p2, out rem);

                Assert.AreEqual(p3, rem);
                AreAlmostRelativeEquals(Polynomial.ZERO, p3);
            }

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, 1.4, 1.3, 1.2);
                Polynomial p2 = new Polynomial(1.6, 1.5, 1.4, 1.3);

                Polynomial p3 = p1 % p2;
                Polynomial rem;
                Polynomial.DivRem(p1, p2, out rem);

                Assert.AreEqual(p3, rem);
                AreAlmostRelativeEquals(new Polynomial(1.5905325443787, 0.0142011834319524, 0.00710059171597607), p3);
            }

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, -1.4, 1.3, 1.2);
                Polynomial p2 = new Polynomial(1.6, 1.5, 1.4);

                Polynomial p3 = p1 % p2;
                Polynomial rem;
                Polynomial.DivRem(p1, p2, out rem);

                Assert.AreEqual(p3, rem);
                AreAlmostRelativeEquals(new Polynomial(4.78483965014577, 4.46946064139942), p3);
            }

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, -1.4, 1.3, 1.2);
                Polynomial p2 = new Polynomial(1.6, 1.5);

                Polynomial p3 = p1 % p2;
                Polynomial rem;
                Polynomial.DivRem(p1, p2, out rem);

                Assert.AreEqual(p3, rem);
                AreAlmostRelativeEquals(new Polynomial(-1.61716148148148), p3);
            }

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, 1.4, 1.3, 1.2);
                Polynomial p2 = new Polynomial(1.6);

                Polynomial p3 = p1 % p2;
                Polynomial rem;
                Polynomial.DivRem(p1, p2, out rem);

                Assert.AreEqual(p3, rem);
                AreAlmostRelativeEquals(Polynomial.ZERO, p3);
            }

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, 1.4, 1.3);
                Polynomial p2 = new Polynomial(1.6, 1.5, 1.4, 1.3, 1.2);

                Polynomial p3 = p1 % p2;
                Polynomial rem;
                Polynomial.DivRem(p1, p2, out rem);

                Assert.AreEqual(p3, rem);
                AreAlmostRelativeEquals(new Polynomial(1.6, 1.5, 1.4, 1.3), p3);

                Assert.AreEqual(new Polynomial(1.6, 1.5, 1.4, 1.3), p1);
                Assert.AreEqual(new Polynomial(1.6, 1.5, 1.4, 1.3, 1.2), p2);
            }

            {
                Polynomial p1 = new Polynomial(1.6, 1.5, 1.4, 1.3, 0);
                Polynomial p2 = new Polynomial(1.6, 1.5, 1.4, 1.3);

                Polynomial p3 = p1 % p2;
                Polynomial rem;
                Polynomial.DivRem(p1, p2, out rem);

                Assert.AreEqual(p3, rem);
                AreAlmostRelativeEquals(Polynomial.ZERO, p3);
            }

            // operator * polynomials
            {
                Polynomial p1 = Polynomial.ZERO;
                Polynomial p2 = Polynomial.ZERO;

                Polynomial p3 = p1 * p2;
                Polynomial p4 = p2 * p1;

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(Polynomial.ZERO, p3);
            }

            {
                Polynomial p1 = Polynomial.ZERO;
                Polynomial p2 = new Polynomial(1.6, 1.5, 1.4, 1.3);

                Polynomial p3 = p1 * p2;
                Polynomial p4 = p2 * p1;

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(Polynomial.ZERO, p3);
            }

            {
                Polynomial p1 = new Polynomial(1.5);
                Polynomial p2 = new Polynomial(1.3);

                Polynomial p3 = p1 * p2;
                Polynomial p4 = p2 * p1;

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(new Polynomial(1.95), p3);
            }

            {
                Polynomial p1 = new Polynomial(1.5);
                Polynomial p2 = new Polynomial(1.4, 1.3);

                Polynomial p3 = p1 * p2;
                Polynomial p4 = p2 * p1;

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(new Polynomial(2.1, 1.95), p3);
            }

            {
                Polynomial p1 = new Polynomial(1.4, 1.5);
                Polynomial p2 = new Polynomial(1.6, 1.3);

                Polynomial p3 = p1 * p2;
                Polynomial p4 = p2 * p1;

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(new Polynomial(2.24, 4.22, 1.95), p3);
            }

            {
                Polynomial p1 = new Polynomial(-0.9, 1.3, 1.4, 1.5);
                Polynomial p2 = new Polynomial(1.6, 1.3);

                Polynomial p3 = p1 * p2;
                Polynomial p4 = p2 * p1;

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(new Polynomial(-1.44, 0.91, 3.93, 4.22, 1.95), p3);

                Assert.AreEqual(p1, new Polynomial(-0.9, 1.3, 1.4, 1.5));
                Assert.AreEqual(p2, new Polynomial(1.6, 1.3));
            }

            {
                Polynomial p1 = new Polynomial(0.9, 1.3, 1.4, 1.5);
                Polynomial p2 = new Polynomial(1.6, 1.3);

                Polynomial p3 = p1 * p2;
                Polynomial p4 = p2 * p1;

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(new Polynomial(1.44, 3.25, 3.93, 4.22, 1.95), p3);
            }

            {
                Polynomial p1 = new Polynomial(-1.3, 1.4, 1.5);
                Polynomial p2 = new Polynomial(1.2, -1.6, 1.3);

                Polynomial p3 = p1 * p2;
                Polynomial p4 = p2 * p1;

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(new Polynomial(-1.56, 3.76, -2.13, -0.580000000000001, 1.95), p3);
            }

            // operator +  
            {
                Polynomial p1 = Polynomial.ZERO;
                Polynomial p2 = Polynomial.ZERO;

                Polynomial p3 = p1 + p2;
                Polynomial p4 = p2 + p1;

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(Polynomial.ZERO, p3);
            }

            {
                Polynomial p1 = Polynomial.ZERO;
                Polynomial p2 = new Polynomial(1.6, 1.5, 1.4, 1.3);

                Polynomial p3 = p1 + p2;
                Polynomial p4 = p2 + p1;

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(new Polynomial(1.6, 1.5, 1.4, 1.3), p3);
            }

            {
                Polynomial p1 = new Polynomial(1.5);
                Polynomial p2 = new Polynomial(-1.3);

                Polynomial p3 = p1 + p2;
                Polynomial p4 = p2 + p1;

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(new Polynomial(0.19999999999999996), p3);
            }

            {
                Polynomial p1 = new Polynomial(1.7, -1.6, 1.5);
                Polynomial p2 = new Polynomial(0.3, -0.2, 0.1, 1.4, 1.3);

                Polynomial p3 = p1 + p2;
                Polynomial p4 = p2 + p1;

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(new Polynomial(2, -1.8, 1.6, 1.4, 1.3), p3);

                Assert.AreEqual(new Polynomial(1.7, -1.6, 1.5), p1);
                Assert.AreEqual(new Polynomial(0.3, -0.2, 0.1, 1.4, 1.3), p2);
            }

            {
                Polynomial p1 = new Polynomial(0.3, 0.2, -0.1, 1.4, 1.3);
                Polynomial p2 = new Polynomial(-0.5, 0.4, 0.3, 2.4, 2.3);

                Polynomial p3 = p1 + p2;
                Polynomial p4 = p2 + p1;

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(new Polynomial(-0.2, 0.6, 0.2, 3.8, 3.6), p3);
            }

            {
                Polynomial p1 = new Polynomial(0.3, 0.2, -0.1, 1.4, 1.3);
                Polynomial p2 = -new Polynomial(0.3, 0.2, -0.1, 1.4, 1.3);

                Polynomial p3 = p1 + p2;
                Polynomial p4 = p2 + p1;

                Assert.AreEqual(p3, p4);
                AreAlmostRelativeEquals(Polynomial.ZERO, p3);
            }

            // operator -
            {
                Polynomial p1 = Polynomial.ZERO;
                Polynomial p2 = Polynomial.ZERO;

                Polynomial p3 = p1 - p2;
                Polynomial p4 = p2 - p1;

                AreAlmostRelativeEquals(Polynomial.ZERO, p3);
                AreAlmostRelativeEquals(Polynomial.ZERO, p4);
            }

            {
                Polynomial p1 = Polynomial.ZERO;
                Polynomial p2 = new Polynomial(1.6, 1.5, 1.4, 1.3);

                Polynomial p3 = p1 - p2;
                Polynomial p4 = p2 - p1;

                AreAlmostRelativeEquals(new Polynomial(-1.6, -1.5, -1.4, -1.3), p3);
                AreAlmostRelativeEquals(-new Polynomial(-1.6, -1.5, -1.4, -1.3), p4);
            }

            {
                Polynomial p1 = new Polynomial(1.5);
                Polynomial p2 = new Polynomial(-1.3);

                Polynomial p3 = p1 - p2;
                Polynomial p4 = p2 - p1;

                AreAlmostRelativeEquals(new Polynomial(2.8), p3);
                AreAlmostRelativeEquals(-new Polynomial(2.8), p4);
            }

            {
                Polynomial p1 = new Polynomial(1.7, -1.6, 1.5);
                Polynomial p2 = new Polynomial(0.3, -0.2, 0.1, 1.4, 1.3);

                Polynomial p3 = p1 - p2;
                Polynomial p4 = p2 - p1;

                AreAlmostRelativeEquals(new Polynomial(1.4, -1.4, 1.4, -1.4, -1.3), p3);
                AreAlmostRelativeEquals(-new Polynomial(1.4, -1.4, 1.4, -1.4, -1.3), p4);

                Assert.AreEqual(new Polynomial(1.7, -1.6, 1.5), p1);
                Assert.AreEqual(new Polynomial(0.3, -0.2, 0.1, 1.4, 1.3), p2);
            }

            {
                Polynomial p1 = new Polynomial(0.3, 0.2, -0.1, 1.4, 1.3);
                Polynomial p2 = new Polynomial(-0.5, 0.4, 0.3, 2.4, 2.3);

                Polynomial p3 = p1 - p2;
                Polynomial p4 = p2 - p1;

                AreAlmostRelativeEquals(new Polynomial(0.8, -0.2, -0.4, -1, -1), p3);
                AreAlmostRelativeEquals(-new Polynomial(0.8, -0.2, -0.4, -1, -1), p4);
            }

            {
                Polynomial p1 = new Polynomial(1.3, 1.4, -0.1, 0.2, 0.3);
                Polynomial p2 = new Polynomial(1.3, 1.4, -0.1, 0.2, 0.3);

                Polynomial p3 = p1 - p2;
                Polynomial p4 = p2 - p1;

                AreAlmostRelativeEquals(Polynomial.ZERO, p3);
                AreAlmostRelativeEquals(Polynomial.ZERO, p4);
            }

            // operator - unary

            {
                Polynomial p = Polynomial.ZERO;
                AreAlmostRelativeEquals(p, - -p);
                AreAlmostRelativeEquals(-p, Polynomial.ZERO - p);
            }

            {
                Polynomial p = new Polynomial(1.0);
                AreAlmostRelativeEquals(p, - -p);
                AreAlmostRelativeEquals(-p, Polynomial.ZERO - p);
            }

            {
                Polynomial p = new Polynomial(6.7, -4.5, 3.4, -2.0);
                AreAlmostRelativeEquals(p, - -p);
                AreAlmostRelativeEquals(-p, Polynomial.ZERO - p);

                Polynomial pp = -p;
                Assert.AreEqual(new Polynomial(6.7, -4.5, 3.4, -2.0), p);
            }

            // operator * const

            {
                Polynomial p1 = Polynomial.ZERO * 6;
                Polynomial p2 = 6 * Polynomial.ZERO;

                AreAlmostRelativeEquals(Polynomial.ZERO, p1);
                AreAlmostRelativeEquals(p1, p2);
            }

            {
                Polynomial p1 = new Polynomial(1.0) * 5;
                Polynomial p2 = 5 * new Polynomial(1.0);

                AreAlmostRelativeEquals(new Polynomial(5.0), p1);
                AreAlmostRelativeEquals(p1, p2);
            }

            {
                Polynomial p = new Polynomial(6.7, -4.5, 3.4, -2.0);
                Polynomial p1 = p * -2;
                Polynomial p2 = -2 * new Polynomial(6.7, -4.5, 3.4, -2.0);

                AreAlmostRelativeEquals(new Polynomial(-13.4, 9, -6.8, 4.0), p1);
                AreAlmostRelativeEquals(p1, p2);
                Assert.AreEqual(new Polynomial(6.7, -4.5, 3.4, -2.0), p);
            }

            {
                Polynomial p = new Polynomial(6.7, -4.5, 3.4, -2.0) * 0;

                AreAlmostRelativeEquals(Polynomial.ZERO, p);
            }

            // operator / const

            {
                Polynomial p = Polynomial.ZERO / 6;

                AreAlmostRelativeEquals(Polynomial.ZERO, p);
            }

            {
                Polynomial p = new Polynomial(5.0) / 5;

                AreAlmostRelativeEquals(new Polynomial(1.0), p);
            }

            {
                Polynomial pp = new Polynomial(-13.4, 9, -6.8, 4.0);
                Polynomial p = pp / -2;

                AreAlmostRelativeEquals(new Polynomial(6.7, -4.5, 3.4, -2.0), p);
                Assert.AreEqual(new Polynomial(-13.4, 9, -6.8, 4.0), pp);
            }

            {
                Polynomial p = new Polynomial(-13.4, 9, -6.8, 4.0) / Double.PositiveInfinity;

                AreAlmostRelativeEquals(Polynomial.ZERO, p);
            }

            // Pow 

            {
                Polynomial p1 = p_1;
                Polynomial p2 = p1 ^ 0;

                AreAlmostRelativeEquals(Polynomial.ONE, p2);
            }

            {
                Polynomial p1 = p_1;
                Polynomial p2 = p1 ^ 1;

                AreAlmostRelativeEquals(p_1, p2);
            }

            {
                Polynomial p1 = p_1 * p_1;
                Polynomial p2 = p1 ^ 1;

                AreAlmostRelativeEquals(p_1 * p_1, p2);
            }

            {
                Polynomial p1 = p_1 * p_1;
                Polynomial p2 = p1 ^ 2;

                AreAlmostRelativeEquals(p_1 * p_1 * p_1 * p_1, p2);
            }

            {
                Polynomial p1 = p_1;
                Polynomial p2 = p1 ^ 4;

                AreAlmostRelativeEquals(p_1 * p_1 * p_1 * p_1, p2);
            }

            // GCD

            {
                Polynomial A = p_1;
                Polynomial B = p_2;
                Polynomial GCD = Polynomial.GCD(A, B);
                Polynomial expected = Polynomial.ONE;

                AreAlmostRelativeEquals(expected, GCD);
            }

            {
                Polynomial A = p_2;
                Polynomial B = p_1;
                Polynomial GCD = Polynomial.GCD(A, B);
                Polynomial expected = Polynomial.ONE;

                AreAlmostRelativeEquals(expected, GCD);
            }

            {
                Polynomial A = p_1;
                Polynomial B = p_1;
                Polynomial GCD = Polynomial.GCD(A, B);
                Polynomial expected = p_1.Normalize();

                AreAlmostRelativeEquals(expected, GCD);
            }

            {
                Polynomial A = p_1;
                Polynomial B = Polynomial.ZERO;
                Polynomial GCD = Polynomial.GCD(A, B);
                Polynomial expected = p_1.Normalize();

                AreAlmostRelativeEquals(expected, GCD);
            }

            {
                Polynomial A = p_1;
                Polynomial B = Polynomial.ONE;
                Polynomial GCD = Polynomial.GCD(A, B);
                Polynomial expected = Polynomial.ONE;

                AreAlmostRelativeEquals(expected, GCD);
            }

            {
                Polynomial A = Polynomial.ZERO;
                Polynomial B = p_2;
                Polynomial GCD = Polynomial.GCD(A, B);
                Polynomial expected = p_2.Normalize();

                AreAlmostRelativeEquals(expected, GCD);
            }

            {
                Polynomial A = Polynomial.ONE;
                Polynomial B = p_2;
                Polynomial GCD = Polynomial.GCD(A, B);
                Polynomial expected = Polynomial.ONE;

                AreAlmostRelativeEquals(expected, GCD);
            }

            {
                Polynomial A = p_1 * p_1;
                Polynomial B = p_1;
                Polynomial GCD = Polynomial.GCD(A, B);
                Polynomial expected = p_1.Normalize();

                AreAlmostRelativeEquals(expected, GCD);
            }

            {
                Polynomial A = 2 * p_1 * p_1;
                Polynomial B = p_1;
                Polynomial GCD = Polynomial.GCD(A, B);
                Polynomial expected = p_1.Normalize();

                AreAlmostRelativeEquals(expected, GCD);
            }

            {
                Polynomial A = 2 * p_1 * p_1;
                Polynomial B = 2 * p_1;
                Polynomial GCD = Polynomial.GCD(A, B);
                Polynomial expected = p_1.Normalize();

                AreAlmostRelativeEquals(expected, GCD);
            }

            {
                Polynomial A = p_1 ^ 3;
                Polynomial B = p_1 ^ 4;
                Polynomial GCD = Polynomial.GCD(A, B);
                Polynomial expected = (p_1 ^ 3).Normalize();

                AreAlmostRelativeEquals(expected, GCD);
            }

            {
                Polynomial A = p_1 * p_2 * p_2 * p_2;
                Polynomial B = A.Differentiate();
                Polynomial GCD = Polynomial.GCD(A, B);
                Polynomial expected = (p_2 * p_2).Normalize();

                AreAlmostRelativeEquals(expected, GCD);
            }

            {
                Polynomial A = p_1 * p_1 * p_2 * p_2;
                Polynomial B = A.Differentiate();
                Polynomial GCD = Polynomial.GCD(A, B);
                Polynomial expected = (p_1 * p_2).Normalize();

                AreAlmostRelativeEquals(expected, GCD);
            }

            {
                Polynomial A = p_1 * p_2 * (p_4 ^ 3);
                Polynomial B = p_1 * (p_2 ^ 2) * (p_3 ^ 3) * (p_4 ^ 4);
                Polynomial GCD = Polynomial.GCD(A, B, 1e-9);
                Polynomial expected = (p_1 * p_2 * (p_4 ^ 3)).Normalize();

                AreAlmostRelativeEquals(expected, GCD);
            }

            {
                Polynomial A = p_1 * p_2 * (p_4 ^ 3);
                Polynomial B = A.Differentiate();
                Polynomial GCD = Polynomial.GCD(A, B);
                Polynomial expected = (p_4 ^ 2).Normalize();

                AreAlmostRelativeEquals(expected, GCD);
            }

            {
                Polynomial A = p_1 * p_2 * (p_4 ^ 2) * (p_5 ^ 3) * (p_6 ^ 2);
                Polynomial B = p_1 * (p_2 ^ 2) * (p_4 ^ 3) * (p_5 ^ 2) * (p_6 ^ 2);
                Polynomial GCD = Polynomial.GCD(A, B, 1e-7);
                Polynomial expected = (p_1 * p_2 * (p_4 ^ 2) * (p_5 ^ 2) * (p_6 ^ 2)).Normalize();

                AreAlmostRelativeEquals(expected, GCD);
            }

            {
                Polynomial A = p_1 * p_2 * (p_4 ^ 2) * (p_5 ^ 2);
                Polynomial B = A.Differentiate();
                Polynomial GCD = Polynomial.GCD(A, B, 1e-11);
                Polynomial expected = (p_4 * p_5).Normalize();

                AreAlmostRelativeEquals(expected, GCD);
            }

            {
                Polynomial A = p_1 * p_2 * (p_4 ^ 2) * (p_5 ^ 3);
                Polynomial B = A.Differentiate();
                Polynomial GCD = Polynomial.GCD(A, B, 1e-9);
                Polynomial expected = (p_4 * (p_5 ^ 2)).Normalize();

                AreAlmostRelativeEquals(expected, GCD, 1e-11);
            }

            // RemoveZeroes.

            {
                Polynomial p1 = new Polynomial(Constants.DOUBLE_PRECISION / 10);
                Polynomial p2 = p1.RemoveZeroes();

                AreAlmostRelativeEquals(p1, p2);
            }

            {
                Polynomial p1 = new Polynomial(Constants.DOUBLE_PRECISION / 10, 1);
                Polynomial p2 = p1.RemoveZeroes();

                AreAlmostRelativeEquals(new Polynomial(1), p2);
            }

            {
                Polynomial p1 = new Polynomial(Constants.DOUBLE_PRECISION / 10, Constants.DOUBLE_PRECISION / 10, 2, 4);
                Polynomial p2 = p1.RemoveZeroes();

                AreAlmostRelativeEquals(new Polynomial(2, 4), p2);
            }

            {
                Polynomial p1 = new Polynomial(Constants.DOUBLE_PRECISION / 10, Constants.DOUBLE_PRECISION * 10, 2, 4);
                Polynomial p2 = p1.RemoveZeroes();

                AreAlmostRelativeEquals(new Polynomial(Constants.DOUBLE_PRECISION * 10, 2, 4), p2);
            }
        }
    }
}